﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using static net.xBei.Helper.ArrayHelper;

namespace net.xBei.Helper {
    /// <summary>
    /// 数组、列表（List）相关操作
    /// </summary>
    public static class ArrayHelper {
        /// <summary>
        /// 生成从<paramref name="min"/>开始到<paramref name="max"/>结束的数列。
        /// Range(1,3)=>[1,2,3]
        /// </summary>
        /// <param name="min"></param>
        /// <param name="max"></param>
        /// <returns></returns>
        public static IEnumerable<int> Range(int min, int max) {
            var l = new List<int>();
            for (var i = min; i <= max; i++) {
                l.Add(i);
            }
            return l;
        }

        /// <summary>
        /// 非空
        /// <see cref="string.IsNullOrWhiteSpace(string?)"/>
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static bool NotEmpty(this IEnumerable<string> source)
            => source.Any(s => !string.IsNullOrWhiteSpace(s));
        /// <summary>
        /// 排除空字符
        /// <see cref="string.IsNullOrWhiteSpace(string?)"/>
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static IEnumerable<string> RemoveEmptyString(this IEnumerable<string> source)
            => source.Where(s => !string.IsNullOrWhiteSpace(s));

        /// <summary>
        /// 判断两个系列的内容是否一模一样（长度相同，系列a的每个项目都在系列b中）
        /// 与<see cref="Enumerable.SequenceEqual{TSource}(IEnumerable{TSource}, IEnumerable{TSource})"/>不同，该方法不考虑顺序。
        /// 使用默认比较器。
        /// <seealso cref="Enumerable.Contains{TSource}(IEnumerable{TSource}, TSource)"/>
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="listA">第一个系列</param>
        /// <param name="listB">第二个系列</param>
        /// <returns></returns>
        public static bool SameAs<T>(this IEnumerable<T> listA, IEnumerable<T> listB) where T : struct
            => listA.Count() == listB.Count() && (!listA.Any() || listA.All(va => listB.Contains(va)));
        /// <summary>
        /// 判断两个系列的内容是否一模一样（长度相同，系列a的每个项目都在系列b中）
        /// 与<see cref="Enumerable.SequenceEqual{TSource}(IEnumerable{TSource}, IEnumerable{TSource})"/>不同，该方法不考虑顺序。
        /// 使用默认比较器。
        /// <seealso cref="Enumerable.Contains{TSource}(IEnumerable{TSource}, TSource)"/>
        /// </summary>
        /// <param name="listA">第一个系列</param>
        /// <param name="listB">第二个系列</param>
        /// <returns></returns>
        public static bool SameAs(this IEnumerable<string> listA, IEnumerable<string> listB)
            => listA.Count() == listB.Count() && (!listA.Any() || listA.All(va => listB.Contains(va)));
        /// <summary>
        /// 判断两个系列是否不一样
        /// 判断依据：长度不同或者两个系列里的项目和对方有区别。
        /// 与<see cref="Enumerable.SequenceEqual{TSource}(IEnumerable{TSource}, IEnumerable{TSource})"/>不同，该方法不考虑顺序。
        /// 使用默认比较器。
        /// <seealso cref="Enumerable.Except{TSource}(IEnumerable{TSource}, IEnumerable{TSource})"/>
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="lista">第一个系列</param>
        /// <param name="listb">第二个系列</param>
        /// <returns></returns>
        public static bool NotSameAs<T>(this IEnumerable<T> lista, IEnumerable<T> listb) where T : struct
            => lista.Count() != listb.Count() || lista.Except(listb).Any() || listb.Except(lista).Any();
        /// <summary>
        /// 判断两个系列是否不一样
        /// 判断依据：长度不同或者两个系列里的项目和对方有区别。
        /// 与<see cref="Enumerable.SequenceEqual{TSource}(IEnumerable{TSource}, IEnumerable{TSource})"/>不同，该方法不考虑顺序。
        /// 使用默认比较器。
        /// <seealso cref="Enumerable.Except{TSource}(IEnumerable{TSource}, IEnumerable{TSource})"/>
        /// </summary>
        /// <param name="lista">第一个系列</param>
        /// <param name="listb">第二个系列</param>
        /// <returns></returns>
        public static bool NotSameAs(this IEnumerable<string> lista, IEnumerable<string> listb)
            => lista.Count() != listb.Count() || lista.Except(listb).Any() || listb.Except(lista).Any();
        /// <summary>
        /// 移除队列中的“空”（null）项目
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <returns></returns>
        public static IEnumerable<T> RemoveNull<T>(this IEnumerable<T> list) => list.Where(o => o != null);

        /// <summary>
        /// 返回<paramref name="list"/>中的第一个非空字符串（<see cref="string.IsNullOrWhiteSpace(string?)"/>），
        /// 如果找不到非空字符串则返回<paramref name="dv"/>
        /// </summary>
        /// <param name="list"></param>
        /// <param name="dv"></param>
        /// <returns></returns>
        public static string FirstNotEmpty(this IEnumerable<string> list, string? dv = null) 
            => list.FirstOrDefault(s => !string.IsNullOrWhiteSpace(s)) ?? dv ?? string.Empty;
        /// <summary>
        /// 按下标获取系列中数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <param name="index">如果超出范围，会自动使用最接近的</param>
        /// <returns></returns>
        public static T GetElementAt<T>(this IEnumerable<T> list, int index)
            => list.ElementAt(index >= list.Count() ? list.Count() - 1 : Math.Max(0, index));

        /// <summary>
        /// 快速校验
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="arr"></param>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public static bool IsValid<T>(this IEnumerable<T> arr, Func<T, bool> predicate) {
            return arr != null && arr.Any() && arr.All(predicate);
        }
        /// <summary>
        /// 快速校验
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="arr"></param>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public static (bool succ, string msg) IsValid<T>(this IEnumerable<T> arr, Func<T, (bool succ, string msg)> predicate) {
            if (arr != null && arr.Any()) {
                //arr.All(predicate);
                foreach (var item in arr) {
                    var r = predicate.Invoke(item);
                    if (r.succ == false) return r;
                }
                return (true, string.Empty);
            } 
            
                return (false, "数据不能为空");
            
        }

        /// <summary>
        /// 是否为空
        /// <paramref name="arr"/> == null 或者 <paramref name="arr"/>.Count() == 0 返回 true
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="arr">arr == null 或者 arr.Count() == 0 返回true</param>
        /// <returns></returns>
        public static bool IsNullOrEmpty<T>(this IEnumerable<T> arr) => (arr?.Count() ?? 0) < 1;
        /// <summary>
        /// 是否有数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="arr"></param>
        /// <returns></returns>
        public static bool IsNotEmpty<T>(this IEnumerable<T> arr) => (arr?.Count() ?? 0) > 0;
        /// <summary>
        /// 变量数组，对每个项目执行指定方法
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <param name="callBack"></param>
        /// <returns></returns>
        public static IEnumerable<T> ForEach<T>(this IEnumerable<T> list, Action<T, int> callBack) {
            var i = 0;
            foreach (var k in list) {
                callBack.Invoke(k, i++);
            }
            return list;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <param name="callBack"></param>
        /// <returns></returns>
        public static IEnumerable<T> ForEach<T>(this IEnumerable<T> list, Action<T> callBack) {
            foreach (var k in list) {
                callBack.Invoke(k);
            }
            return list;
        }
        public static async Task<IEnumerable<T>> ForEachAsync<T>(this Task<IEnumerable<T>> list, Func<T, Task> callBack) {
            return await ForEachAsync(await list, callBack);
        }
        public static async Task<IEnumerable<T>> ForEachAsync<T>(this IEnumerable<T> list, Func<T, Task> callBack) {
            foreach (var k in list) {
                await callBack.Invoke(k);
            }
            return list;
        }
        public static Task<IEnumerable<TSource>> ForEachAsync<TSource>(this Task<IEnumerable<TSource>> sources, Action<TSource> selector)
            => ForEachAsync(sources, (item, index) => selector.Invoke(item));
        public static async Task<IEnumerable<TSource>> ForEachAsync<TSource>(this Task<IEnumerable<TSource>> sources, Action<TSource, int> selector)
            => (await sources).ForEach(selector);
        /// <summary>
        /// 把列表的每个项目转换成字串然后连接起来
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <param name="separator"></param>
        /// <returns></returns>
        public static string JoinBy<T>(this IEnumerable<T> list, string separator)            => string.Join(separator, list);
        /// <summary>
        /// 把列表的每个项目转换成字串然后连接起来
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <param name="separator"></param>
        /// <returns></returns>
        public static string JoinBy<T>(this IEnumerable<T> list, char separator)            => string.Join(separator, list);
        /// <summary>
        /// 查找符合条件的项目，然后返回索引
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public static int FindIndex<T>(this IEnumerable<T> list, Func<T, bool> predicate) {
            var i = 0;
            foreach (var k in list) {
                if (predicate.Invoke(k)) return i;
                i++;
            }
            return -1;
        }
        public static IOrderedEnumerable<T> SortBy<T, Tkey>(this IEnumerable<T> list, Func<T, Tkey> keySelector, IComparer<Tkey> comparer) {
            return list.OrderBy(keySelector, comparer);
        }
        public static async Task<IOrderedEnumerable<T>> SortByAsync<T, Tkey>(this Task<T[]> list, Func<T, Tkey> keySelector, IComparer<Tkey> comparer) {
            return (await list).OrderBy(keySelector, comparer);
        }
        /// <summary>
        /// 排序（string）
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <param name="keySelector"></param>
        /// <param name="ignoreCase"></param>
        /// <param name="asc"></param>
        /// <returns></returns>
        public static IOrderedEnumerable<T> SortBy<T>(this IEnumerable<T> list, Func<T, string> keySelector, bool ignoreCase, bool asc = true)
            => asc
                ? list.OrderBy(keySelector, new StringComparer(ignoreCase))
                : list.OrderByDescending(keySelector, new StringComparer(ignoreCase));
        /// <summary>
        /// 排序（int）
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <param name="keySelector"></param>
        /// <param name="asc"></param>
        /// <returns></returns>
        public static IOrderedEnumerable<T> SortBy<T>(this IEnumerable<T> list, Func<T, int> keySelector, bool asc = true)
            => asc
                ? list.OrderBy(keySelector, new IntComparer())
                : list.OrderByDescending(keySelector, new IntComparer());
        /// <summary>
        /// 按指定的顺序排序（倒序）
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <param name="orderList"></param>
        /// <param name="keySelector"></param>
        /// <returns></returns>
        public static IOrderedEnumerable<T> OrderByDescending<T>(this IEnumerable<T> list, int[] orderList, Func<T, int> keySelector)
            => list.OrderByDescending(keySelector, new IntComparerByList(orderList));
        /// <summary>
        /// 按指定的顺序排序（顺序）
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <param name="orderList"></param>
        /// <param name="keySelector"></param>
        /// <returns></returns>
        public static IOrderedEnumerable<T> OrderBy<T>(this IEnumerable<T> list, int[] orderList, Func<T, int> keySelector)
            => list.OrderBy(keySelector, new IntComparerByList(orderList));
        public static async Task<IOrderedEnumerable<T>> SortByAsync<T>(this Task<T[]> list, Func<T, int> keySelector, bool asc = true)
            => asc
                ? (await list).OrderBy(keySelector, new IntComparer())
                : (await list).OrderByDescending(keySelector, new IntComparer());

        public static IOrderedEnumerable<T> SortBy<T>(this IEnumerable<T> list, Func<T, decimal> keySelector, bool asc = true)
            => asc
                ? list.OrderBy(keySelector, new DecimalComparer())
                : list.OrderByDescending(keySelector, new DecimalComparer());
        public static IOrderedEnumerable<T> SortByThen<T>(this IOrderedEnumerable<T> list, Func<T, int> keySelector, bool asc = true)
            => asc
                ? list.ThenBy(keySelector, new IntComparer())
                : list.ThenByDescending(keySelector, new IntComparer());
        /// <summary>
        /// 
        /// </summary>
        /// <param name="list"></param>
        /// <param name="found"></param>
        /// <returns></returns>
        public static int IndexOf(this int[] list, int found) => Array.IndexOf(list, found);
        /// <summary>
        /// 按添加设置系列里面的项目的值（替换）只替换找到的第一个
        /// 如果系列里面没有找到指定的值则把新值插入到最后
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list">系列</param>
        /// <param name="predicate">条件</param>
        /// <param name="newValue">新值</param>
        /// <returns>返回一个新队列</returns>
        public static IEnumerable<T> Set<T>(this IEnumerable<T> list, Func<T, bool> predicate, T newValue) {
            if (list.Any(predicate) == false) {
                return list.Concat(new[] { newValue });
            }
            var c = list.Count();
            var i = 0;
            //for (var i = 0; i < c; i++) {
            //    var item = list.ElementAt(i);
            foreach (var item in list) {
                if (predicate.Invoke(item) == false) {
                    i++;
                    continue;
                }
                if (i == 0) {
                    return new[] { newValue }.Concat(list.Skip(1));
                }
                if (i + 1 == c) {
                    return list.Take(c - 1).Concat(new[] { newValue });
                }
                return list.Take(i).Concat(new[] { newValue }).Concat(list.Skip(i + 1));
            }
            return list;
        }
        /// <summary>
        /// 简化List.Contains
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="Tkey"></typeparam>
        /// <param name="list"></param>
        /// <param name="keySelector"></param>
        /// <param name="comparer"></param>
        /// <returns></returns>
        public static bool Contains<T, Tkey>(this IEnumerable<T> list, Func<T, Tkey> keySelector, Tkey comparer) {
            return list.Select(keySelector).Contains(comparer);
        }
        /// <summary>
        /// 清理数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public static IEnumerable<T> Clear<T>(this IEnumerable<T> list, Func<T, bool> predicate) => list.Where(predicate);
        /// <summary>
        /// 清理值为空的数据
        /// </summary>
        /// <param name="valuePair"></param>
        /// <returns></returns>
        public static bool ClearKeyValue(KeyValuePair<string, string> valuePair) => !string.IsNullOrWhiteSpace(valuePair.Value);


        public static IComparer<string> GetStringComparer(bool ignoreCase) => new StringComparer(ignoreCase);

#pragma warning disable CS1591 // 缺少对公共可见类型或成员的 XML 注释
        public class StringEqComparer : IEqualityComparer<string> {
#pragma warning restore CS1591 // 缺少对公共可见类型或成员的 XML 注释
            /// <inheritdoc/>
            public bool Equals(string? x, string? y) => string.Equals(x, y);
            /// <inheritdoc/>
            public int GetHashCode(string obj) => obj.GetHashCode();
        }
        /// <summary>
        /// 移除空字符串项目
        /// </summary>
        /// <param name="list"></param>
        /// <returns></returns>
        public static IEnumerable<string> RemoveEmptyItems(this IEnumerable<string> list) => list.Where(s => !string.IsNullOrWhiteSpace(s));
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <returns></returns>
        public static IEnumerable<T> RemoveEmptyItems<T>(this IEnumerable<T> list) => list.Where(s => s != null);
        /// <summary>
        /// 
        /// </summary>
        public class StringComparer : IComparer<string> {
            private readonly bool ignoreCase;
            /// <summary>
            /// 
            /// </summary>
            /// <param name="ignoreCase"></param>
            public StringComparer(bool ignoreCase) {
                this.ignoreCase = ignoreCase;
            }
            /// <inheritdoc/>
            public int Compare(string? x, string? y) => string.Compare(x, y, ignoreCase);
        }
        /// <summary>
        /// 
        /// </summary>
        public class IntComparerByList : IComparer<int> {
            private readonly int[] list;
            /// <summary>
            /// 
            /// </summary>
            /// <param name="list"></param>
            public IntComparerByList(int[] list) {
                this.list = list;
            }
            /// <inheritdoc/>
            public int Compare(int x, int y) {
                var indexX = list.IndexOf(x);
                var indexY = list.IndexOf(y);
                //Console.WriteLine($"{x}={indexX}, {y} = {indexY}, {indexX.CompareTo(indexY)}");
                return indexY.CompareTo(indexX);
            }
        }
        /// <summary>
        /// 
        /// </summary>
        public class IntComparer : IComparer<int> {
            /// <inheritdoc/>
            public int Compare(int x, int y) => x.CompareTo(y);
        }
        /// <summary>
        /// 
        /// </summary>
        public class DecimalComparer : IComparer<decimal> {
            /// <summary>
            /// 
            /// </summary>
            /// <param name="x"></param>
            /// <param name="y"></param>
            /// <returns></returns>
            public int Compare(decimal x, decimal y) => x.CompareTo(y);
        }
        #region Select
        public static async Task<IEnumerable<TResult>> SelectAsync<TSource, TResult>(this Task<TSource[]> source,
                                                                                     Func<TSource, Task<TResult>> selector) {
            return await SelectAsync(await source, async (item, index) => await selector.Invoke(item));
        }
        public static async Task<IEnumerable<TResult>> SelectAsync<TSource, TResult>(this Task<TSource[]> source,
                                                                             Func<TSource, TResult> selector) {
            return (await source).Select((item) => selector.Invoke(item));
        }
        public static Task<IEnumerable<TResult>> SelectAsync<TSource, TResult>(this TSource[] source,
                                                                               Func<TSource, Task<TResult>> selector) {
            return SelectAsync(source, async (item, index) => await selector.Invoke(item));
        }

        public static Task<IEnumerable<TResult>> SelectAsync<TSource, TResult>(this IEnumerable<TSource> source,
                                                                               Func<TSource, Task<TResult>> selector) {
            return SelectAsync(source, async (item, index) => await selector.Invoke(item));
        }
        public static async Task<IEnumerable<TResult>> SelectAsync<TSource, TResult>(this IEnumerable<TSource> source,
                                                                                     Func<TSource, int, Task<TResult>> selector) {
            var arr = await Task.WhenAll(source.Select((item, index) => selector.Invoke(item, index)));
            return arr;
        }

        public static async Task<IEnumerable<TResult>> SelectAsync<TSource, TResult>(this Task<IEnumerable<TSource>> source,
                                                                               Func<TSource, TResult> selector)
            => (await source).Select(selector);
        public static async Task<IEnumerable<TResult>> SelectAsync<TSource, TResult>(this Task<IEnumerable<TSource>> source,
                                                                                     Func<TSource, int, TResult> selector)
            => (await source).Select(selector);

        public static async Task<IEnumerable<TResult>> SelectAsync<TSource, TResult>(this Task<IOrderedEnumerable<TSource>> source,
                                                                                     Func<TSource, TResult> selector)
            => (await source).Select(selector);

        /// <summary>
        /// 按条件选择，连续调用：<see cref="Enumerable.Where{TSource}(IEnumerable{TSource}, Func{TSource, bool})"/>和
        /// <see cref="Enumerable.Select{TSource, TResult}(IEnumerable{TSource}, Func{TSource, TResult})"/>
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="source"></param>
        /// <param name="predicate"></param>
        /// <param name="selector"></param>
        /// <returns></returns>
        public static IEnumerable<TResult> SelectBy<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, bool> predicate, Func<TSource, TResult> selector)
            => source.Where(predicate).Select(selector);
        #endregion

        #region 异步方法
        public static async Task<IEnumerable<TSource>> RemoveNullAsync<TSource>(this Task<IEnumerable<TSource>> source) {
            return (await source).Where(o => o != null);
        }
        public static async Task<IEnumerable<TSource>> WhereAsync<TSource>(this Task<IEnumerable<TSource>> source, Func<TSource, bool> predicate) => (await source).Where(predicate);


        public static async Task<IEnumerable<TSource>> DistinctAsync<TSource>(this Task<IEnumerable<TSource>> sources) => (await sources).Distinct();
        public static async Task<TSource[]> ToArrayAsync<TSource>(this Task<IEnumerable<TSource>> sources) => (await sources).ToArray();
        public static async Task<IEnumerable<TSource>> AsEnumerableAsync<TSource>(this Task<TSource[]> sources) => (await sources).AsEnumerable();
        public static async Task<IEnumerable<TSource>> AsEnumerableAsync<TSource>(this Task<List<TSource>> sources) => (await sources).AsEnumerable();
        public static async Task<List<TSource>> ToListAsync<TSource>(this Task<IEnumerable<TSource>> sources) => (await sources).ToList();

        public static async Task<ILookup<TKey, TElement>> ToLookupAsync<TSource, TKey, TElement>(this Task<IEnumerable<TSource>> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector)
            => (await source).ToLookup(keySelector, elementSelector);
        //public static async Task<ILookup<TKey, TSource>> ToListAsync<TSource, TKey>(this Task<IEnumerable<TSource>> sources) => (await sources).ToLookup();
        #endregion
        public static async Task<TSource> GetItemAtAsync<TSource>(this Task<IEnumerable<TSource>> sources, int index)
            => (await sources).ElementAt(index);
        public static async Task<TSource> GetItemAtAsync<TSource>(this Task<List<TSource>> sources, int index)
            => (await sources).ElementAt(index);
        public static async Task<TSource?> FirstOrDefaultAsync<TSource>(this Task<IEnumerable<TSource>> sources)
            => (await sources).FirstOrDefault();
        public static async Task<TSource?> FirstOrDefaultAsync<TSource>(this Task<List<TSource>> sources)
            => (await sources).FirstOrDefault();
        public static async Task<bool> EqualsAsync(this Task<int> sources, int count) => (await sources) == count;
        public static int DistinctCount<TSource, TResult>(this IEnumerable<TSource> sources, Func<TSource, TResult> selector)
            => sources.Select(selector).Distinct().Count();
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="list"></param>
        /// <param name="compare"></param>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public static TResult? Max<TSource, TResult>(this IEnumerable<TSource> list, Func<TSource, decimal> compare, Func<TSource, TResult> predicate) {
            if (list.Count() < 2) {
                return list.Select(predicate).FirstOrDefault();
            }
            var max = list.ElementAt(0);
            var first = true;
            foreach (var item in list) {
                if (first) { first = false; continue; }
                if (compare.Invoke(item) > compare.Invoke(max)) {
                    max = item;
                }
            }
            return predicate.Invoke(max);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <param name="sources"></param>
        /// <returns></returns>
        public static IEnumerable<TSource> DistinctByComparer<TSource>(this IEnumerable<TSource> sources) where TSource : IDistinctEquality<TSource>
            => sources.Distinct(new DistinctEqualityComparer<TSource>());
        internal class DistinctEqualityComparer<TItem> : IEqualityComparer<TItem> where TItem : IDistinctEquality<TItem> {
            /// <summary>
            /// 
            /// </summary>
            /// <param name="x"></param>
            /// <param name="y"></param>
            /// <returns></returns>
            public bool Equals(TItem? x, TItem? y) {
                if (x == null && y == null) {
                    return true;
                }
                if (x != null && y != null) {
                    return x.DistinctEquality(y);
                }
                return false;
            }

            public int GetHashCode(TItem obj) {
                return obj.GetDistinctEqualityHashCode();
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TItem"></typeparam>
        public interface IDistinctEquality<TItem> {
            /// <summary>
            /// 
            /// </summary>
            /// <param name="item"></param>
            /// <returns></returns>
            bool DistinctEquality(TItem item);
            /// <summary>
            /// 
            /// </summary>
            /// <returns></returns>
            int GetDistinctEqualityHashCode();
        }
    }
}
